home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- ftp.c
-
- This reusable module implements FTP text file transfers to and from memory.
-
- The following functions are exported:
-
- FtpOpen - Open an FTP stream.
- FtpClose - Close an FTP stream.
- FtpGetTextFile - Get a text file.
- FtpSendTextFile - Send a text file.
-
- The following functions are used to get error information:
-
- FtpGetServerErrInfo - Get server error information.
- FtpGetOSErr - Get OS error number.
-
- The NetInit function in module net.c must be called before calling any of
- the functions in this module. You also must call the NetIdle function in your
- idle loop, and the NetTerm function at program termination.
-
- A "stream" is an abstraction representing a bidirectional network connection
- to an FTP server. A stream is represented as a handle of type "FtpStreamHandle".
- These stream handles are opaque. You may copy them and pass them as parameters
- to functions in ftp.c, but you are prohibited from accessing the contents of
- the memory blocks pointed to by the stream handles. Only the functions in
- ftp.c are permitted to manipulate the contents of these blocks.
-
- The functions return a value of type FtpErr as the function result:
-
- ftpNoErr no error occurred
- ftpServerErr server error
- ftpOSErr OS error
-
- If the function result is ftpServerErr, the FtpGetServerErrInfo function should
- be called to get information about the server error. On server errors, the
- stream is still open on return to the caller (except in FtpOpen, which creates the
- stream only if no errors of any kind occur).
-
- If the function result is ftpOSErr, the FtpGetOSErr function should be called
- to get the OS error number:
-
- userCanceledErr if the user canceled the operation
- other any other OS, Toolbox, or MacTCP error code
-
- If the user cancels an operation or any other OS error occurs, the stream
- is aborted and deallocated before returning to the caller. "Aborted" means that
- the server connection is closed abruptly, without going through the usual TCP
- stream teardown process. You must perform careful error checking. The stream is
- deallocated, and must not be reused.
-
- Copyright © 1994, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
-
- #include "def.h"
- #include "ftp.h"
- #include "net.h"
- #include "memutil.h"
-
-
-
- /* Types. */
-
- typedef struct TStream {
- NetStreamHandle netStream; /* net stream handle */
- } TStream, *TStreamPtr, **TStreamHandle;
-
-
-
- /* Global variables. */
-
- static OSErr gErr = noErr; /* OS error code */
- static CStr255 gCommand = ""; /* server command */
- static long gResponseCode = 0; /* server response code */
- static CStr255 gResponse = ""; /* server response message */
-
-
-
- /*----------------------------------------------------------------------------
- FtpOpen
-
- Open an FTP stream.
-
- Entry: host = server host address (domain name or dotted
- decimal IP address).
- username = user name.
- password = password.
-
- Exit: function result = result code.
- stream = handle to opened stream,
- or nil if function result != ftpNoErr.
- ----------------------------------------------------------------------------*/
-
- FtpErr FtpOpen (char *host, char *username, char *password,
- FtpStreamHandle *stream)
- {
- TStreamHandle s;
- unsigned long addr;
- unsigned short port;
- NetStreamHandle netStream;
-
- *stream = nil;
- *gCommand = 0;
-
- gErr = NetNameToAddr(host, kFTPPort, &addr, &port);
- if (gErr != noErr) return ftpOSErr;
-
- gErr = NetOpen(addr, port, &netStream, &gResponseCode, gResponse);
- if (gErr != noErr) return ftpOSErr;
- if (gResponseCode != 220) goto exit1;
-
- sprintf(gCommand, "USER %.250s", username);
- gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) return ftpOSErr;
- if (gResponseCode != 331) goto exit1;
-
- sprintf(gCommand, "PASS %.250s", password);
- gErr = NetCommand(netStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) return ftpOSErr;
- if (gResponseCode != 230) goto exit1;
-
- gErr = MyNewHandle(sizeof(TStream), &s);
- if (gErr != noErr) goto exit2;
-
- (**s).netStream = netStream;
- *stream = (FtpStreamHandle)s;
- return ftpNoErr;
-
- exit1:
-
- NetClose(netStream);
- return ftpServerErr;
-
- exit2:
-
- NetClose(netStream);
- return ftpOSErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- FtpClose
-
- Close an FTP stream.
-
- Entry: stream = handle to stream.
-
- Exit: function result = result code (always ftpNoErr).
- ----------------------------------------------------------------------------*/
-
- FtpErr FtpClose (FtpStreamHandle stream)
- {
- TStreamHandle s;
-
- s = (TStreamHandle)stream;
- NetClose((**s).netStream);
- MyDisposeHandle(s);
- return ftpNoErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- FtpGetTextFile
-
- Get a text file from an FTP server.
-
- Entry: stream = handle to stream.
- path = file path.
-
- Exit: function result = result code.
- text = handle to text.
-
- The text block contains CR line terminators, including a CR terminator
- at the end of the last line.
- ----------------------------------------------------------------------------*/
-
- FtpErr FtpGetTextFile (FtpStreamHandle stream, char *path, Handle *text)
- {
- TStreamHandle s;
- NetStreamHandle controlStream, dataStream;
- unsigned long myAddr;
- unsigned short port;
-
- s = (TStreamHandle)stream;
- controlStream = (**s).netStream;
-
- gErr = NetGetMyAddr(&myAddr);
- if (gErr != noErr) goto exit1;
-
- gErr = NetFTPDataOpen(&port, &dataStream);
- if (gErr != noErr) goto exit1;
-
- sprintf(gCommand, "PORT %hu,%hu,%hu,%hu,%hu,%hu",
- (unsigned short)((myAddr>>24)&0xff),
- (unsigned short)((myAddr>>16)&0xff),
- (unsigned short)((myAddr>>8)&0xff),
- (unsigned short)(myAddr&0xff),
- (unsigned short)((port>>8)&0xff),
- (unsigned short)(port&0xff));
- gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit2;
- if (gResponseCode != 200) goto exit3;
-
- sprintf(gCommand, "RETR %.250s", path);
- gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit2;
- if (gResponseCode != 150 && gResponseCode != 125) goto exit3;
-
- gErr = NetFTPDataWaitForConnection(dataStream);
- if (gErr != noErr) goto exit1;
-
- gErr = NetGetFTPTextFile(dataStream, text);
- if (gErr != noErr) goto exit1;
-
- gErr = NetFTPDataClose(dataStream);
- if (gErr != noErr) goto exit1;
-
- gErr = NetGetExtraResponse(controlStream, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit4;
- if (gResponseCode != 226) return ftpServerErr;
-
- return ftpNoErr;
-
- exit1:
-
- NetClose(controlStream);
- MyDisposeHandle(s);
- return ftpOSErr;
-
- exit2:
-
- NetFTPDataClose(dataStream);
- MyDisposeHandle(s);
- return ftpOSErr;
-
- exit3:
-
- NetFTPDataClose(dataStream);
- return ftpServerErr;
-
- exit4:
-
- MyDisposeHandle(s);
- return ftpOSErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- FtpSendTextFile
-
- Send a text file to an FTP server.
-
- Entry: stream = handle to stream.
- path = file path.
- text = handle to text.
-
- Exit: function result = result code.
-
- The text must contain CR line terminators. If the last line is
- not terminated with a CR, an extra CR terminator is added.
-
- The CR line terminators are converted to CRLF when the file is sent
- over the network to the server. The server converts the CRLF line
- terminators to whatever terminator is used on the host system.
- ----------------------------------------------------------------------------*/
-
- FtpErr FtpSendTextFile (FtpStreamHandle stream, char *path, Handle text)
- {
- TStreamHandle s;
- NetStreamHandle controlStream, dataStream;
- unsigned long myAddr;
- unsigned short port;
-
- s = (TStreamHandle)stream;
- controlStream = (**s).netStream;
-
- gErr = NetGetMyAddr(&myAddr);
- if (gErr != noErr) goto exit1;
-
- gErr = NetFTPDataOpen(&port, &dataStream);
- if (gErr != noErr) goto exit1;
-
- sprintf(gCommand, "PORT %hu,%hu,%hu,%hu,%hu,%hu",
- (unsigned short)((myAddr>>24)&0xff),
- (unsigned short)((myAddr>>16)&0xff),
- (unsigned short)((myAddr>>8)&0xff),
- (unsigned short)(myAddr&0xff),
- (unsigned short)((port>>8)&0xff),
- (unsigned short)(port&0xff));
- gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit2;
- if (gResponseCode != 200) goto exit3;
-
- sprintf(gCommand, "STOR %.250s", path);
- gErr = NetCommand(controlStream, gCommand, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit2;
- if (gResponseCode != 150 && gResponseCode != 125) goto exit3;
-
- gErr = NetFTPDataWaitForConnection(dataStream);
- if (gErr != noErr) goto exit1;
-
- gErr = NetSendFTPTextFile(dataStream, text);
- if (gErr != noErr) goto exit1;
-
- gErr = NetFTPDataClose(dataStream);
- if (gErr != noErr) goto exit1;
-
- gErr = NetGetExtraResponse(controlStream, &gResponseCode, gResponse);
- if (gErr != noErr) goto exit4;
- if (gResponseCode != 226) return ftpServerErr;
-
- return ftpNoErr;
-
- exit1:
-
- NetClose(controlStream);
- MyDisposeHandle(s);
- return ftpOSErr;
-
- exit2:
-
- NetFTPDataClose(dataStream);
- MyDisposeHandle(s);
- return ftpOSErr;
-
- exit3:
-
- NetFTPDataClose(dataStream);
- return ftpServerErr;
-
- exit4:
-
- MyDisposeHandle(s);
- return ftpOSErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- FtpGetServerErrInfo
-
- Get server error information.
-
- Exit: cmd = C-format server command.
- num = server error number.
- msg = C-format server error message.
- ----------------------------------------------------------------------------*/
-
- void FtpGetServerErrInfo (CStr255 cmd, long *num, CStr255 msg)
- {
- strcpy(cmd, gCommand);
- *num = gResponseCode;
- strcpy(msg, gResponse);
- }
-
-
-
- /*----------------------------------------------------------------------------
- FtpGetOSErr
-
- Get the OS error code.
-
- Exit: function result = OS error code.
- ----------------------------------------------------------------------------*/
-
- OSErr FtpGetOSErr (void)
- {
- return gErr;
- }
-